package com.fast.develop.dm.integration;

import cn.hutool.core.io.IoUtil;
import cn.hutool.core.lang.Assert;
import com.fast.develop.dm.core.ModuleConfiguration;
import com.fast.develop.dm.core.MetaDomainConfiguration;
import com.fast.develop.dm.core.persistence.DomainModelManager;
import com.fast.develop.dm.core.properties.DomainRuntimeProperties;
import com.fast.develop.dm.core.xml.generator.ClassGenerator;
import com.fast.develop.dm.integration.web.DomainModelResourcesRest;
import com.fast.develop.dm.integration.web.DomainRequestMappingHandlerMapping;
import com.fast.develop.dm.meta.MetaDomainModel;
import org.springframework.core.io.InputStreamResource;
import org.springframework.core.io.Resource;
import org.springframework.orm.hibernate5.LocalSessionFactoryBean;

import javax.sql.DataSource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;

/**
 * @author 莫寅
 * @createTime 2022-06-08 13:28
 * @desc：
 */
public class HibernateModuleConfiguration implements ModuleConfiguration {

    private MetaDomainConfiguration metaDomainConfiguration;

    private LocalSessionFactoryBean localSessionFactoryBean;

    private DataSource dataSource;

    private String[] packagesToScan;

    private Class[] annotatedClasses;

    private String[] mappingResources;

    private Map properties;

    private boolean enableResourcesRest;


    private DomainRuntimeProperties domainRuntimeProperties = new DomainRuntimeProperties();

    public HibernateModuleConfiguration(MetaDomainConfiguration metaDomainConfiguration) {
        this.metaDomainConfiguration = metaDomainConfiguration;
    }

    @Override
    public MetaDomainConfiguration getMetaDomainConfiguration() {
        return metaDomainConfiguration;
    }

    @Override
    public DataSource getDataSource() {
        return dataSource;
    }

    @Override
    public Map getProperties() {
        return null;
    }


    public void setEnableResourcesRest(boolean enableResourcesRest) {
        this.enableResourcesRest = enableResourcesRest;
    }

    @Override
    public boolean enableResourcesRest() {
        return enableResourcesRest;
    }

    public DomainRuntimeProperties getDomainRuntimeProperties() {
        return domainRuntimeProperties;
    }

    public void setDomainRuntimeProperties(DomainRuntimeProperties domainRuntimeProperties) {
        this.domainRuntimeProperties = domainRuntimeProperties;
    }

    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    public void setPackagesToScan(String[] packagesToScan) {
        this.packagesToScan = packagesToScan;
    }

    public void setAnnotatedClasses(Class[] annotatedClasses) {
        this.annotatedClasses = annotatedClasses;
    }

    public void setMappingResources(String[] mappingResources) {
        this.mappingResources = mappingResources;
    }

    public void setProperties(Map properties) {
        this.properties = properties;
    }


    private LocalSessionFactoryBean localSessionFactoryBean() throws IOException {
        List<Resource> domainModelInputStream = new ArrayList<>();
        List<MetaDomainModel> metaDomainModels =  metaDomainConfiguration.getMetaDomainModels();
        metaDomainModels.forEach(metaDomainModel -> {
            ClassGenerator classGenerator = new ClassGenerator(metaDomainModel);
            String xml = classGenerator.generate();
            Resource resource = new InputStreamResource(IoUtil.toUtf8Stream(xml));
            domainModelInputStream.add(resource);
        });


        LocalSessionFactoryBean localSessionFactoryBean = new LocalSessionFactoryBean();
        localSessionFactoryBean.setPackagesToScan(packagesToScan);
        localSessionFactoryBean.setAnnotatedClasses(annotatedClasses);
        localSessionFactoryBean.setMappingResources(mappingResources);
        localSessionFactoryBean.setMappingLocations(domainModelInputStream.toArray(new Resource[domainModelInputStream.size()]));

        Properties hibernateProperties = new Properties();
        hibernateProperties.putAll(properties);

        localSessionFactoryBean.setHibernateProperties(hibernateProperties);
        localSessionFactoryBean.setDataSource(dataSource);


        return localSessionFactoryBean;
    }

    public void initialize() throws Exception {
        Assert.isFalse(dataSource == null, "datasource is not be null");

        this.localSessionFactoryBean = localSessionFactoryBean();

    }

    public LocalSessionFactoryBean getLocalSessionFactoryBean() {
        return localSessionFactoryBean;
    }
}
